// import com.alibaba.druid.sql.ast.*;
// import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
// import com.alibaba.druid.sql.ast.expr.SQLQueryExpr;
// import com.alibaba.druid.sql.ast.statement.*;
// import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerOutput;
// import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerTop;
// import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt->*;
// import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt->SQLServerExecStatement.SQLServerExecStatement_SQLServerParameter;
// import com.alibaba.druid.sql.parser.*;
// import com.alibaba.druid.util.FnvHash;

// import java.util.Collection;
// import java.util.List;

#include "SQLServerStatementParser.h"
#include "../../../ast/expr/SQLIdentifierExpr.h"
#include "../../../ast/expr/SQLQueryExpr.h"
#include "../ast/SQLServerOutput.h"
#include "../ast/SQLServerTop.h"
#include "../ast/stmt/SQLServerExecStatement.h"
#include "../../../../utils/FnvHash.h"
#include "../../../../utils/StringUtils.h"
#include "SQLServerExprParser.h"
#include "SQLServerSelectParser.h"
#include "../../../ast/statement/SQLIfStatement.h"
#include "../../../ast/statement/SQLScriptCommitStatement.h"
#include "../../../ast/statement/SQLDeclareStatement.h"
#include "../../../ast/statement/SQLColumnConstraint.h"
#include "../../../ast/statement/SQLUpdateStatement.h"
#include "../../../ast/statement/SQLSetStatement.h"
#include "../../../ast/statement/SQLStartTransactionStatement.h"
#include "../../../ast/statement/SQLBlockStatement.h"
#include "../../../ast/statement/SQLCommitStatement.h"
#include "../../../ast/statement/SQLAlterTableDropConstraint.h"
#include "../../../ast/statement/SQLAlterTableStatement.h"
#include "../../../ast/statement/SQLAlterTableDropColumnItem.h"
#include "../../../ast/statement/SQLAlterTableDropIndex.h"
#include "../../../ast/statement/SQLAlterTableDropPrimaryKey.h"
#include "../../../ast/SQLDeclareItem.h"
#include "../ast/stmt/SQLServerWaitForStatement.h"
#include "../ast/stmt/SQLServerInsertStatement.h"
#include "../ast/stmt/SQLServerUpdateStatement.h"
#include "../ast/stmt/SQLServerSetTransactionIsolationLevelStatement.h"
#include "../ast/stmt/SQLServerRollbackStatement.h"

SQLServerStatementParser::SQLServerStatementParser(string_ptr sql)
    : SQLStatementParser(SQLServerExprParser_ptr(new SQLServerExprParser(sql)))
{
}

SQLServerStatementParser::SQLServerStatementParser(string_ptr sql, SQLParserFeature_list_ptr features)
    : SQLStatementParser(SQLServerExprParser_ptr(new SQLServerExprParser(sql, features)))
{
}

SQLSelectParser_ptr SQLServerStatementParser::createSQLSelectParser()
{
  return SQLServerSelectParser_ptr(new SQLServerSelectParser(this->exprParser, selectListCache));
}

SQLServerStatementParser::SQLServerStatementParser(Lexer_ptr lexer)
    : SQLStatementParser(SQLServerExprParser_ptr(new SQLServerExprParser(lexer)))
{
}

BOOL_ptr SQLServerStatementParser::parseStatementListDialect(SQLStatement_list_ptr statementList)
{
  if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
  {
    SQLStatement_ptr stmt = parseSelect();
    statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(FnvHash::Constants::EXEC) || lexer->identifierEquals(FnvHash::Constants::EXECUTE))
  {
    lexer->nextToken();

    SQLServerExecStatement_ptr execStmt = SQLServerExecStatement_ptr(new SQLServerExecStatement());
    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      lexer->nextToken();
      this->parseExecParameter(execStmt->getParameters(), execStmt);
      accept(Token::RPAREN);
    }
    else
    {
      SQLName_ptr sqlNameName = this->exprParser->name();

      if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
      {
        lexer->nextToken();
        execStmt->setReturnStatus(sqlNameName);
        execStmt->setModuleName(this->exprParser->name());
      }
      else
      {
        execStmt->setModuleName(sqlNameName);
      }

      if (lexer->token()->name->c_str() != Token::SEMI.name->c_str() &&
          lexer->token()->name->c_str() != Token::XEOF.name->c_str())
      {
        this->parseExecParameter(execStmt->getParameters(), execStmt);
      }
    }
    statementList->push_back(execStmt);
    return BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::DECLARE.name->c_str())
  {
    statementList->push_back(this->parseDeclare());
    return BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    statementList->push_back(this->parseIf());
    return BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::BEGIN.name->c_str())
  {
    statementList->push_back(this->parseBlock());
    return BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::COMMIT.name->c_str())
  {
    statementList->push_back(this->parseCommit());
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(FnvHash::Constants::WAITFOR))
  {
    statementList->push_back(this->parseWaitFor());
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(FnvHash::Constants::GO))
  {
    lexer->nextToken();

    SQLStatement_ptr stmt = SQLScriptCommitStatement_ptr(new SQLScriptCommitStatement());
    statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  return BOOL::FALSE;
}

/**
 * SQLServer parse Parameter statement support out type
 */
void SQLServerStatementParser::parseExecParameter(SQLServerExecStatement_SQLServerParameter_list_ptr exprCol, SQLObject_ptr parent)
{
  if (lexer->token()->name->c_str() == Token::RPAREN.name->c_str() || lexer->token()->name->c_str() == Token::RBRACKET.name->c_str())
  {
    return;
  }

  if (lexer->token()->name->c_str() == Token::XEOF.name->c_str())
  {
    return;
  }
  SQLServerExecStatement_SQLServerParameter_ptr param = SQLServerExecStatement_SQLServerParameter_ptr(new SQLServerExecStatement_SQLServerParameter());
  SQLExpr_ptr expr = this->exprParser->getExpr();
  expr->setParent(parent);
  param->setExpr(expr);
  if (lexer->token()->name->c_str() == Token::OUT.name->c_str())
  {
    param->setType(BOOL::TRUE);
    accept(Token::OUT);
  }
  exprCol->push_back(param);
  while (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
  {
    lexer->nextToken();
    param = SQLServerExecStatement_SQLServerParameter_ptr(new SQLServerExecStatement_SQLServerParameter());
    expr = this->exprParser->getExpr();
    expr->setParent(parent);
    param->setExpr(expr);
    if (lexer->token()->name->c_str() == Token::OUT.name->c_str())
    {
      param->setType(BOOL::TRUE);
      accept(Token::OUT);
    }
    exprCol->push_back(param);
  }
}

SQLStatement_ptr SQLServerStatementParser::parseDeclare()
{
  this->accept(Token::DECLARE);

  SQLDeclareStatement_ptr declareStatement = SQLDeclareStatement_ptr(new SQLDeclareStatement());

  for (;;)
  {
    SQLDeclareItem_ptr item = SQLDeclareItem_ptr(new SQLDeclareItem());
    declareStatement->addItem(item);

    item->setName(this->exprParser->name());

    if (lexer->token()->name->c_str() == Token::AS.name->c_str())
    {
      lexer->nextToken();
    }

    if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
    {
      lexer->nextToken();
      item->setType(SQLDeclareItem::Type::TABLE);

      if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
      {
        lexer->nextToken();

        for (;;)
        {
          if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str() //
              || lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
          {
            SQLColumnDefinition_ptr column = this->exprParser->parseColumn();
            item->getTableElementList()->push_back(column);
          }
          else if (lexer->token()->name->c_str() == Token::PRIMARY.name->c_str()   //
                   || lexer->token()->name->c_str() == Token::UNIQUE.name->c_str() //
                   || lexer->token()->name->c_str() == Token::CHECK.name->c_str()  //
                   || lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str())
          {
            SQLConstraint_ptr constraint = this->exprParser->parseConstaint();
            constraint->setParent(item);
            item->getTableElementList()->push_back(std::dynamic_pointer_cast<SQLTableElement>(constraint));
          }
          else if (lexer->token()->name->c_str() == Token::TABLESPACE.name->c_str())
          {
            std::string tmp = "TODO ";
            tmp += encode_util::UnicodeToUTF8(lexer->info());
            throw new ParserException(make_string_ptr(tmp));
          }
          else
          {
            SQLColumnDefinition_ptr column = this->exprParser->parseColumn();
            item->getTableElementList()->push_back(column);
          }

          if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
          {
            lexer->nextToken();

            if (lexer->token()->name->c_str() == Token::RPAREN.name->c_str())
            {
              break;
            }
            continue;
          }

          break;
        }
        accept(Token::RPAREN);
      }
      break;
    }
    else if (lexer->token()->name->c_str() == Token::CURSOR.name->c_str())
    {
      item->setType(SQLDeclareItem::Type::CURSOR);
      lexer->nextToken();
    }
    else
    {
      item->setType(SQLDeclareItem::Type::LOCAL);
      item->setDataType(this->exprParser->parseDataType());
      if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
      {
        lexer->nextToken();
        item->setValue(this->exprParser->expr());
      }
    }

    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }
    else
    {
      break;
    }
  }
  return declareStatement;
}

SQLStatement_ptr SQLServerStatementParser::parseInsert()
{
  SQLServerInsertStatement_ptr insertStatement = SQLServerInsertStatement_ptr(new SQLServerInsertStatement());

  if (lexer->token()->name->c_str() == Token::INSERT.name->c_str())
  {
    accept(Token::INSERT);
  }

  SQLStatementParser::parseInsert0(insertStatement);
  return insertStatement;
}

void SQLServerStatementParser::parseInsert0(SQLInsertInto_ptr insert, BOOL_ptr acceptSubQuery)
{
  SQLServerInsertStatement_ptr insertStatement = std::dynamic_pointer_cast<SQLServerInsertStatement>(insert);

  SQLServerTop_ptr top = this->getExprParser()->parseTop();
  if (top != nullptr)
  {
    insertStatement->setTop(top);
  }

  if (lexer->token()->name->c_str() == Token::INTO.name->c_str())
  {
    lexer->nextToken();
  }

  SQLName_ptr tableName = this->exprParser->name();
  insertStatement->setTableName(tableName);

  if (lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
  {
    insertStatement->setAlias(tableAlias());
  }

  parseInsert0_hinits(insertStatement);

  if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str() &&
   !StringUtils::equalsIgnoreCase(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())), make_string_ptr("OUTPUT")))
  {
    insertStatement->setAlias(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())));
    lexer->nextToken();
  }

  if (lexer->token()->name->c_str() == (Token::LPAREN.name->c_str()))
  {
    lexer->nextToken();
    this->exprParser->exprList(insertStatement->getColumns(), insertStatement);
    accept(Token::RPAREN);
  }

  SQLServerOutput_ptr output = this->getExprParser()->parserOutput();
  if (output != nullptr)
  {
    insertStatement->setOutput(output);
  }

  if (lexer->token()->name->c_str() == Token::VALUES.name->c_str())
  {
    lexer->nextToken();

    for (;;)
    {
      accept(Token::LPAREN);
      SQLInsertStatement_ValuesClause_ptr values = SQLInsertStatement_ValuesClause_ptr(new SQLInsertStatement_ValuesClause());
      this->exprParser->exprList(values->getValues(), values);
      insertStatement->addValueCause(values);
      accept(Token::RPAREN);

      if (!parseCompleteValues && insertStatement->getValuesList()->size() >= parseValuesSize)
      {
        lexer->skipToEOF();
        break;
      }

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        continue;
      }
      else
      {
        break;
      }
    }
  }
  else if (acceptSubQuery && (lexer->token()->name->c_str() == Token::SELECT.name->c_str() || lexer->token()->name->c_str() == Token::LPAREN.name->c_str()))
  {
    SQLQueryExpr_ptr queryExpr = std::dynamic_pointer_cast<SQLQueryExpr>(this->exprParser->expr());
    insertStatement->setQuery(queryExpr->getSubQuery());
  }
  else if (lexer->token()->name->c_str() == Token::DEFAULT.name->c_str())
  {
    lexer->nextToken();
    accept(Token::VALUES);
    insertStatement->setDefaultValues(BOOL::TRUE);
  }
}

SQLUpdateStatement_ptr SQLServerStatementParser::createUpdateStatement()
{
  return SQLServerUpdateStatement_ptr(new SQLServerUpdateStatement());
}

SQLUpdateStatement_ptr SQLServerStatementParser::parseUpdateStatement()
{
  SQLServerUpdateStatement_ptr udpateStatement = SQLServerUpdateStatement_ptr(new SQLServerUpdateStatement());

  accept(Token::UPDATE);

  SQLServerTop_ptr top = this->getExprParser()->parseTop();
  if (top != nullptr)
  {
    udpateStatement->setTop(top);
  }

  SQLTableSource_ptr tableSource = this->exprParser->createSelectParser()->parseTableSource();
  udpateStatement->setTableSource(tableSource);

  parseUpdateSet(udpateStatement);

  SQLServerOutput_ptr output = this->getExprParser()->parserOutput();
  if (output != nullptr)
  {
    udpateStatement->setOutput(output);
  }

  if (lexer->token()->name->c_str() == Token::FROM.name->c_str())
  {
    lexer->nextToken();
    SQLTableSource_ptr from = this->exprParser->createSelectParser()->parseTableSource();
    udpateStatement->setFrom(from);
  }

  if (lexer->token()->name->c_str() == (Token::WHERE.name->c_str()))
  {
    lexer->nextToken();
    udpateStatement->setWhere(this->exprParser->expr());
  }

  return udpateStatement;
}

// @Override
SQLServerExprParser_ptr SQLServerStatementParser::getExprParser()
{
  return std::dynamic_pointer_cast<SQLServerExprParser>(exprParser);
}

SQLStatement_ptr SQLServerStatementParser::parseSet()
{
  accept(Token::SET);

  if (lexer->identifierEquals(FnvHash::Constants::TRANSACTION))
  {
    lexer->nextToken();
    acceptIdentifier("ISOLATION");
    acceptIdentifier("LEVEL");

    SQLServerSetTransactionIsolationLevelStatement_ptr stmt = SQLServerSetTransactionIsolationLevelStatement_ptr(new SQLServerSetTransactionIsolationLevelStatement());

    if (lexer->identifierEquals(make_string_ptr("READ")))
    {
      lexer->nextToken();

      if (lexer->identifierEquals(make_string_ptr("UNCOMMITTED")))
      {
        stmt->setLevel(make_string_ptr("READ UNCOMMITTED"));
        lexer->nextToken();
      }
      else if (lexer->identifierEquals(make_string_ptr("COMMITTED")))
      {
        stmt->setLevel(make_string_ptr("READ COMMITTED"));
        lexer->nextToken();
      }
      else
      {
        std::string tmp = "UNKOWN TRANSACTION LEVEL : ";
        tmp += encode_util::UnicodeToUTF8(*lexer->stringVal());
        tmp += ", ";
        tmp += encode_util::UnicodeToUTF8(lexer->info());
        throw new ParserException(make_string_ptr(tmp));
      }
    }
    else if (lexer->identifierEquals(make_string_ptr("SERIALIZABLE")))
    {
      stmt->setLevel(make_string_ptr("SERIALIZABLE"));
      lexer->nextToken();
    }
    else if (lexer->identifierEquals(make_string_ptr("SNAPSHOT")))
    {
      stmt->setLevel(make_string_ptr("SNAPSHOT"));
      lexer->nextToken();
    }
    else if (lexer->identifierEquals(make_string_ptr("REPEATABLE")))
    {
      lexer->nextToken();
      if (lexer->identifierEquals(make_string_ptr("READ")))
      {
        stmt->setLevel(make_string_ptr("REPEATABLE READ"));
        lexer->nextToken();
      }
      else
      {
        std::string tmp = "UNKOWN TRANSACTION LEVEL : ";
        tmp += encode_util::UnicodeToUTF8(*lexer->stringVal());
        tmp += ", ";
        tmp += encode_util::UnicodeToUTF8(lexer->info());
        throw new ParserException(make_string_ptr(tmp));
      }
    }
    else
    {
      std::string tmp = "UNKOWN TRANSACTION LEVEL : ";
      tmp += encode_util::UnicodeToUTF8(*lexer->stringVal());
      tmp += ", ";
      tmp += encode_util::UnicodeToUTF8(lexer->info());
      throw new ParserException(make_string_ptr(tmp));
    }

    return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::STATISTICS))
  {
    lexer->nextToken();

    SQLSetStatement_ptr stmt = SQLSetStatement_ptr(new SQLSetStatement());

    if (lexer->identifierEquals(make_string_ptr("IO")) ||
        lexer->identifierEquals(make_string_ptr("XML")) ||
        lexer->identifierEquals(make_string_ptr("PROFILE")) ||
        lexer->identifierEquals(make_string_ptr("TIME")))
    {
      std::string tmp = "STATISTICS ";
      tmp += StringUtils::toUpper(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())))->c_str();
      SQLExpr_ptr target = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(make_string_ptr(tmp)));

      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::ON.name->c_str())
      {
        stmt->set(target, SQLIdentifierExpr_ptr(new SQLIdentifierExpr(make_string_ptr("ON"))));
        lexer->nextToken();
      }
      else if (lexer->identifierEquals(FnvHash::Constants::OFF))
      {
        stmt->set(target, SQLIdentifierExpr_ptr(new SQLIdentifierExpr(make_string_ptr("OFF"))));
        lexer->nextToken();
      }
    }
    return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::IDENTITY_INSERT))
  {
    SQLSetStatement_ptr stmt = SQLSetStatement_ptr(new SQLSetStatement());
    stmt->setOption(SQLSetStatement_Option::IDENTITY_INSERT);

    lexer->nextToken();
    SQLName_ptr table = this->exprParser->name();

    if (lexer->token()->name->c_str() == Token::ON.name->c_str())
    {
      SQLExpr_ptr value = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(make_string_ptr("ON")));
      stmt->set(table, value);
      lexer->nextToken();
    }
    else if (lexer->identifierEquals(FnvHash::Constants::OFF))
    {
      SQLExpr_ptr value = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(make_string_ptr("OFF")));
      stmt->set(table, value);
      lexer->nextToken();
    }
    return stmt;
  }

  if (lexer->token()->name->c_str() == Token::VARIANT.name->c_str())
  {
    SQLSetStatement_ptr stmt = SQLSetStatement_ptr(new SQLSetStatement(getDbType()));
    parseAssignItems(stmt->getItems(), stmt);
    return stmt;
  }
  else
  {
    SQLSetStatement_ptr stmt = SQLSetStatement_ptr(new SQLSetStatement());
    SQLExpr_ptr target = this->exprParser->expr();

    if (lexer->token()->name->c_str() == Token::ON.name->c_str())
    {
      stmt->set(target, SQLIdentifierExpr_ptr(new SQLIdentifierExpr(make_string_ptr("ON"))));
      lexer->nextToken();
    }
    else if (lexer->identifierEquals(make_string_ptr("OFF")))
    {
      stmt->set(target, SQLIdentifierExpr_ptr(new SQLIdentifierExpr(make_string_ptr("OFF"))));
      lexer->nextToken();
    }
    else
    {
      stmt->set(target, this->exprParser->expr());
    }
    return stmt;
  }
}

SQLIfStatement_ptr SQLServerStatementParser::parseIf()
{
  accept(Token::IF);

  SQLIfStatement_ptr stmt = SQLIfStatement_ptr(new SQLIfStatement());

  stmt->setCondition(this->exprParser->expr());

  this->parseStatementList(stmt->getStatements(), 1, stmt);

  if (lexer->token()->name->c_str() == Token::SEMI.name->c_str())
  {
    lexer->nextToken();
  }

  if (lexer->token()->name->c_str() == Token::ELSE.name->c_str())
  {
    lexer->nextToken();

    SQLIfStatement_Else_ptr elseItem = SQLIfStatement_Else_ptr(new SQLIfStatement_Else());
    this->parseStatementList(elseItem->getStatements(), 1, elseItem);
    stmt->setElseItem(elseItem);
  }

  return stmt;
}

SQLStatement_ptr SQLServerStatementParser::parseBlock()
{
  accept(Token::BEGIN);

  if (lexer->identifierEquals(make_string_ptr("TRANSACTION")) || lexer->identifierEquals(make_string_ptr("TRAN")))
  {
    lexer->nextToken();

    SQLStartTransactionStatement_ptr startTrans = SQLStartTransactionStatement_ptr(new SQLStartTransactionStatement(dbType));

    if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
    {
      SQLName_ptr name = this->exprParser->name();
      startTrans->setName(name);
    }
    return startTrans;
  }

  SQLBlockStatement_ptr block = SQLBlockStatement_ptr(new SQLBlockStatement());
  parseStatementList(block->getStatementList());

  accept(Token::END);

  return block;
}

SQLStatement_ptr SQLServerStatementParser::parseCommit()
{
  acceptIdentifier("COMMIT");

  SQLCommitStatement_ptr stmt = SQLCommitStatement_ptr(new SQLCommitStatement());

  if (lexer->identifierEquals(make_string_ptr("WORK")))
  {
    lexer->nextToken();
    stmt->setWork(BOOL::TRUE);
  }

  if (lexer->identifierEquals(make_string_ptr("TRAN")) || lexer->identifierEquals(make_string_ptr("TRANSACTION")))
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str() || lexer->token()->name->c_str() == Token::VARIANT.name->c_str())
    {
      stmt->setTransactionName(this->exprParser->expr());
    }

    if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
    {
      lexer->nextToken();
      accept(Token::LPAREN);
      acceptIdentifier("DELAYED_DURABILITY");
      accept(Token::EQ);
      stmt->setDelayedDurability(this->exprParser->expr());
      accept(Token::RPAREN);
    }
  }

  return stmt;
}

SQLStatement_ptr SQLServerStatementParser::parseRollback()
{
  acceptIdentifier("ROLLBACK");

  SQLServerRollbackStatement_ptr stmt = SQLServerRollbackStatement_ptr(new SQLServerRollbackStatement());

  if (lexer->identifierEquals(make_string_ptr("WORK")))
  {
    lexer->nextToken();
    stmt->setWork(BOOL::TRUE);
  }

  if (lexer->identifierEquals(make_string_ptr("TRAN")) || lexer->identifierEquals(make_string_ptr("TRANSACTION")))
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str() || lexer->token()->name->c_str() == Token::VARIANT.name->c_str())
    {
      stmt->setName(this->exprParser->expr());
    }
  }

  return stmt;
}

SQLServerWaitForStatement_ptr SQLServerStatementParser::parseWaitFor()
{
  acceptIdentifier("WAITFOR");

  SQLServerWaitForStatement_ptr stmt = SQLServerWaitForStatement_ptr(new SQLServerWaitForStatement());

  if (lexer->identifierEquals(make_string_ptr("DELAY")))
  {
    lexer->nextToken();
    stmt->setDelay(this->exprParser->expr());
  }

  if (lexer->identifierEquals(make_string_ptr("TIME")))
  {
    lexer->nextToken();
    stmt->setTime(this->exprParser->expr());
  }

  if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
  {
    lexer->nextToken();
    if (lexer->identifierEquals(make_string_ptr("TIMEOUT")))
    {
      lexer->nextToken();
      stmt->setTimeout(this->exprParser->expr());
    }
  }

  return stmt;
}

void SQLServerStatementParser::parseAlterDrop(SQLAlterTableStatement_ptr stmt)
{
  lexer->nextToken();
  if (lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str())
  {
    lexer->nextToken();
    SQLAlterTableDropConstraint_ptr item = SQLAlterTableDropConstraint_ptr(new SQLAlterTableDropConstraint());
    item->setConstraintName(this->exprParser->name());
    stmt->addItem(item);
  }
  else if (lexer->token()->name->c_str() == Token::COLUMN.name->c_str())
  {
    lexer->nextToken();
    SQLAlterTableDropColumnItem_ptr item = SQLAlterTableDropColumnItem_ptr(new SQLAlterTableDropColumnItem());

    SQLName_ptr name = exprParser->name();
    name->setParent(item);
    item->addColumn(name);
    while (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();

      if (lexer->token()->name->c_str() == Token::COLUMN.name->c_str())
      {
        lexer->nextToken();
      }
      name = exprParser->name();
      name->setParent(item);
      item->addColumn(name);
    }

    stmt->addItem(item);
  }
  else if (lexer->token()->name->c_str() == Token::INDEX.name->c_str())
  {
    lexer->nextToken();
    SQLName_ptr indexName = this->exprParser->name();
    SQLAlterTableDropIndex_ptr item = SQLAlterTableDropIndex_ptr(new SQLAlterTableDropIndex());
    item->setIndexName(indexName);
    stmt->addItem(item);
  }
  else if (lexer->token()->name->c_str() == Token::PRIMARY.name->c_str())
  {
    lexer->nextToken();
    accept(Token::KEY);
    SQLAlterTableDropPrimaryKey_ptr item = SQLAlterTableDropPrimaryKey_ptr(new SQLAlterTableDropPrimaryKey());
    stmt->addItem(item);
  }
  else
  {
    std::string tmp = "TODO : ";
    tmp += encode_util::UnicodeToUTF8(lexer->info());
    throw new ParserException(make_string_ptr(tmp));
  }
}
